package com.scnlf.scnlf.portal.core.business.event.manager.loan.impl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.scnlf.scnlf.portal.core.business.common.enums.FlowTypeEnum;
import com.scnlf.scnlf.portal.core.business.event.assemble.EventAssemble;
import com.scnlf.scnlf.portal.core.business.event.assemble.LoanEventAssemble;
import com.scnlf.scnlf.portal.core.business.event.dto.EventDTO;
import com.scnlf.scnlf.portal.core.business.event.dto.loan.request.LoanOpenRequest;
import com.scnlf.scnlf.portal.core.business.event.entity.EventEntity;
import com.scnlf.scnlf.portal.core.business.event.manager.loan.ILoanEventService;
import com.scnlf.scnlf.portal.core.business.event.param.loan.LoanOptionEvent;
import com.scnlf.scnlf.portal.core.business.event.service.IEventService;
import com.scnlf.scnlf.portal.core.business.loan.entity.LoanEntity;
import com.scnlf.scnlf.portal.core.business.loan.entity.LoanPositionEntity;
import com.scnlf.scnlf.portal.core.business.loan.entity.LoanTicketEntity;
import com.scnlf.scnlf.portal.core.business.loan.service.ILoanPositionService;
import com.scnlf.scnlf.portal.core.business.loan.service.ILoanService;
import com.scnlf.scnlf.portal.core.business.loan.service.ILoanTicketService;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class LoanEventServiceImpl implements ILoanEventService {

  private final IEventService eventService;

  private final ILoanTicketService loanTicketService;

  private final ILoanService loanService;

  private final ILoanPositionService loanPositionService;

  /**
   * 使用事件解耦
   */
  private final ApplicationEventPublisher eventPublisher;

  private final EventAssemble eventAssemble;

  @Override
  public EventDTO loanOpen(LoanOpenRequest openParam) {
    LoanTicketEntity loanTicket = loanTicketService.getById(openParam.getLoanTicketId());
//    Set<LoanEntity> loanEntities = loanService.getByLoanTicketId(openParam.getLoanTicketId());
//    long usedQuantity = loanEntities.stream().mapToLong(LoanEntity::getLiveQty).count();
    long usedQuantity = loanService.getUserLoanQuantity(openParam.getLoanTicketId());
    loanTicketService.validEnableLoan(loanTicket, openParam.getQuantity(), usedQuantity);

    // 开仓生成一个开仓事件
    EventEntity event = eventService.insertEvent(
        LoanEventAssemble.assembleOpenLoanEvent(openParam, loanTicket));

    EventDTO eventDTO = eventAssemble.toDTO(event);

    // 发布审批任务
    eventPublisher.publishEvent(new LoanOptionEvent(this, LoanEventAssemble.assembleLoanOpenEvent(event)));
    return eventDTO;
  }

  @Override
  public FlowTypeEnum getExamineStatus(Long eventId) {
    return FlowTypeEnum.CONFIRMED;
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public EventEntity loanConfirm(Long eventId) {
    EventEntity openLoanEvent = eventService.getById(eventId);

    if(Objects.isNull(openLoanEvent)){
      throw new RuntimeException("事件不存在");
    }

    if(Objects.isNull(openLoanEvent) || FlowTypeEnum.COMMITTED != openLoanEvent.getFlowStatus()){
      throw new RuntimeException("已确认，忽略确认审批");
    }

    LoanTicketEntity loanTicket = loanTicketService.getById(openLoanEvent.getLoanTicketId());
//    Set<LoanEntity> loanEntities = loanService.getByLoanTicketId(openLoanEvent.getLoanTicketId());
//    long usedQuantity = loanEntities.stream().mapToLong(LoanEntity::getLiveQty).count();
    long usedQuantity = loanService.getUserLoanQuantity(openLoanEvent.getLoanTicketId());
    loanTicketService.validEnableLoan(loanTicket, openLoanEvent.getQuantity(), usedQuantity);

    // 1 审批通过
    openLoanEvent.setFlowStatus(FlowTypeEnum.CONFIRMED);

    // 2 新增约券合约
    LoanEntity loan = loanService.insertLoan(LoanEventAssemble.assembleOpenLoan(openLoanEvent));

    // 3 没有持仓的话，则新增下约券持仓
    LoanPositionEntity loanPosition = loanPositionService.getLoanPosition(loan.getCustomerNo(),
        loan.getSymbol());

    if(Objects.isNull(loanPosition)){
      log.info("insert loan position. customerNo = {}, symbol = {}", loan.getCustomerNo(), loan.getSymbol());
      loanPositionService.insertLoanPosition(LoanEventAssemble.assembleLoanPosition(loan));
    }
    return openLoanEvent;
  }

  @Override
  public EventEntity loanConfirmWithFail(Long eventId) {
    try {
      return SpringUtil.getBean(ILoanEventService.class).loanConfirm(eventId);
    } catch (Exception e){
      EventEntity openLoanEvent = eventService.getById(eventId);
      openLoanEvent.setFlowStatus(FlowTypeEnum.REJECTED);
      openLoanEvent.setMemo(CharSequenceUtil.sub(e.getMessage(), 0, 255));
      eventService.updateEvent(openLoanEvent);
      return openLoanEvent;
    }
  }

  @Override
  public void loanClosing() {

  }

}
